import { XWorkInstance } from '@/ts/base/schema';
import { IGroup, ITarget, IWork, XCollection } from '../../..';
import { kernel, model, schema } from '../../../../base';
import { entityOperates } from '../../../public';
import { FileInfo, IFileInfo } from '../../../thing/fileinfo';
import { ReceptionStatus, getStatus } from './status';

type Base = model.ReceptionContentBase<model.TaskContentType>;

export interface IReception<C extends Base = Base> extends IFileInfo<schema.XReception> {
  /** 键 */
  key: string;
  /** 期数 */
  period: string;
  /** 办事 */
  workId: string;
  /** 操作空间 */
  target: ITarget;
  /** 任务文件群 */
  group: IGroup;
  /** 元数据 */
  metadata: schema.XReception;
  /** 内容 */
  data: C;
  /** 办事对象 */
  work: IWork | undefined;
  /** 接收集合 */
  coll: XCollection<schema.XReception>;
  /** 状态 */
  status: ReceptionStatus;
  /** 加载办事信息 */
  loadWork(reload?: boolean): Promise<IWork | undefined>;
  /** 加载办事实例 */
  loadInstanceDetail(instanceId: string): Promise<XWorkInstance | undefined>;
  /** 提交（更新流程实例ID） */
  submit(instanceId: string): Promise<boolean>;
  /** 完成（更新数据ID） */
  complete(thingId: Dictionary<string[]>): Promise<boolean>;
  /** 驳回 */
  reject(): Promise<boolean>;
  /**
   * 移交任务
   * @param userId 用户Id，不传则移交给自己
   */
  transfer(userId?: string): Promise<boolean>;
  /** 变更（重新发起） */
  change(): Promise<boolean>;
  /** 保存草稿 ID */
  draft(id: string): Promise<schema.XReception | undefined>;
}

export class Reception<C extends Base = Base>
  extends FileInfo<schema.XReception>
  implements IReception<C>
{
  constructor(_metadata: schema.XReception, target: ITarget, isMySpace = true) {
    super(_metadata, target.directory);
    this.isMySpace = isMySpace;
    this.group = target.targets.find((t) => t.id == this.metadata.sessionId) as IGroup;
    if (this.group) {
      this.publicReceptionColl = this.group.directory.resource.genTargetColl(
        '-' + this.coll.collName,
      );
    } else {
      console.warn('找不到接收任务的群聊');
    }
  }
  get data() {
    return this.metadata.content as C;
  }
  group: IGroup;

  publicReceptionColl: XCollection<schema.XReception> | null = null;
  /** 是否从我的单位空间中加载 */
  readonly isMySpace: boolean;
  work: IWork | undefined;
  private _workLoaded = false;
  get cacheFlag() {
    return 'work-reception';
  }
  get code() {
    return this.metadata.period;
  }
  get name() {
    return this.period + this.metadata.name;
  }
  get period() {
    return this.metadata.period;
  }
  get workId() {
    return this.metadata.content.workId;
  }

  get status() {
    return getStatus(this.metadata);
  }

  get coll() {
    return this.target.resource.receptionColl;
  }
  get groupTags() {
    const tags: string[] = [this.metadata.content.type];
    if (this.metadata.belongId != this.userId) {
      if (this.metadata.content.type == model.TaskContentType.Report) {
        tags.push(this.metadata.content.treeNode.name);
      } else {
        tags.push(this.target.user.findShareById(this.metadata.belongId)?.name);
      }
    } else {
      tags.push(this.target.name);
    }
    return tags;
  }
  override operates(): model.OperateModel[] {
    return [
      entityOperates.Open,
      entityOperates.Remark,
      entityOperates.QrCode,
      entityOperates.HardDelete,
    ];
  }
  async loadWork(reload?: boolean | undefined): Promise<IWork | undefined> {
    if (reload || !this._workLoaded) {
      this._workLoaded = true;
      if (!this.group) {
        console.warn('找不到接收任务群聊的会话，无法加载办事');
        return;
      }
      for (const application of await this.group.directory.loadAllApplication()) {
        const work = await application.searchFile(application.id, this.workId, 'or');
        if (work) {
          this.work = work as IWork;
          return this.work;
        }
      }
    }
    return this.work;
  }
  async delete(): Promise<boolean> {
    return await this.hardDelete();
  }
  async hardDelete(): Promise<boolean> {
    const success = await this.coll.remove(this.metadata);
    if (success) {
      await this.publicReceptionColl?.remove(this.metadata);
      await this.coll.notity({ data: this.metadata, operate: 'remove' });
    }
    return success;
  }

  async loadInstanceDetail(instanceId: string): Promise<XWorkInstance | undefined> {
    const belongId = this.metadata.content.treeNode.belongId;
    // 先查群里
    let detail = await kernel.findInstance(this.metadata.sessionId, belongId, instanceId);

    if (!detail) {
      // 再查自己的
      detail = await kernel.findInstance(belongId, belongId, instanceId);
    }
    return detail;
  }

  async submit(instanceId: string) {
    this.metadata.instanceId = instanceId;
    this.metadata.isReject = false;
    const data = this.isMySpace ? await this.coll.replace(this.metadata) : this.metadata;
    if (data) {
      await this.publicReceptionColl?.replace(data);
      return await this.coll.notity({ data, operate: 'update' }, true);
    }
    return false;
  }

  async complete(thingId: Dictionary<string[]>): Promise<boolean> {
    this.metadata.thingId = thingId;
    this.metadata.isReject = false;
    delete this.metadata.previousInstanceId;
    const data = this.isMySpace ? await this.coll.replace(this.metadata) : this.metadata;
    if (data) {
      await this.publicReceptionColl?.replace(data);
      return await this.coll.notity({ data, operate: 'update' }, true);
    }
    return false;
  }

  async reject(): Promise<boolean> {
    this.metadata.isReject = true;
    const data = this.isMySpace ? await this.coll.replace(this.metadata) : this.metadata;
    if (data) {
      await this.publicReceptionColl?.replace(data);
      return await this.coll.notity({ data, operate: 'update' }, true);
    }
    return false;
  }

  async change(): Promise<boolean> {
    if (!this.metadata.thingId) {
      return false;
    }

    this.metadata.receiveUserId = this.userId;
    this.metadata.previousInstanceId = this.metadata.instanceId;
    this.metadata.isReject = false;
    delete this.metadata.instanceId;
    // delete this.metadata.thingId;

    const data = this.isMySpace ? await this.coll.replace(this.metadata) : this.metadata;
    if (data) {
      await this.publicReceptionColl?.replace(data);
      return await this.coll.notity({ data, operate: 'update' }, true);
    }
    return false;
  }

  async transfer(userId?: string): Promise<boolean> {
    this.metadata.receiveUserId = userId || this.userId;
    const data = this.isMySpace ? await this.coll.replace(this.metadata) : this.metadata;
    if (data) {
      await this.publicReceptionColl?.replace(data);
      return await this.coll.notity({ data, operate: 'update' }, true);
    }
    return false;
  }

  draft(id: string): Promise<schema.XReception | undefined> {
    return this.coll.update(this.metadata.id, { _set_: { draftId: id } });
  }
}
